//
//  TYSpriteLayer.m
//  AngerDragon
//
//  Created by gaotime_macbook_2 on 11-12-14.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "TYSpriteLayerSingleton.h"
#import "cocos2d.h"

#import "ScreenSpritesLayer.h"

 

#import "TYDataSolidifyProtocol.h"
#import "TYScenarioInterpretationProtocol.h"
#import "TYMapProtocol.h"
#import "TYSpriteLayerProtocol.h"

#import "TYStateSystem.h"

#import "TYAIProtocol.h"
#import "TYBeHurtProtocol.h"
#import "TYCollisionProtocol.h"
#import "TYHurtValueProtocol.h"
#import "TYUsePropsProtocol.h"
#import "TYEnemyBulletCollisionToTarget.h"
#import "TYPlayerBulletCollisionToTarget.h"

#import "TYLifeSystemProtocol.h"

#import "TYPlayerCommunicateProtocol.h"/// 跟player通信的协议

@implementation TYSpriteLayerSingleton
static TYSpriteLayerSingleton *myInstance = nil;



/// ios实现单例, 要这样做, 因为没有私有构造的概念
+(id)alloc {
	NSAssert(myInstance == nil, @"Attempted to allocate a second instance of a singleton.");
	return [super alloc];
}

/// 单例方法
+ (id<TYSpriteLayerProtocol>) sharedInstance {
	if (nil == myInstance) {
		
		myInstance = [[[self class] alloc] init];
	}
	
	return myInstance;
}



- (id) init {
	
	if ((self = [super init])) {
		CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
		
		
	}
	
	return self;
}

- (void) dealloc {
	CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
	
	/// 
	myInstance = nil;
	
	
	[super dealloc];
}

#pragma mark 实现 对外的接口行为
- (void) spriteLayerLoop:(ccTime) delta {
	
	/// 针对接口编程, 而不是针对实现编程
	/// 通常的做法是, 在客户端代码中不声明特定具体类的变量, 而只使用协议或抽象类定义的接口.
	
	/// 可被player攻击的精灵集合
	CCArray *a_p_can_be_attacked_sprite_array 
		= [ScreenSpritesLayer sharedScreenSpritesLayer].m_p_can_be_attacked_sprite_array;
	/// 敌人子弹集合
	CCArray *a_p_enemy_bullet_array 
		= [ScreenSpritesLayer sharedScreenSpritesLayer].m_p_enemy_bullet_array;
	/// player子弹集合
	CCArray *a_p_player_bullet_array 
		= [ScreenSpritesLayer sharedScreenSpritesLayer].m_p_player_bullet_array;
	/// player
	id<TYPlayerCommunicateProtocol> a_player_communicate 
		= [TYPlayer getPlayerCommunicateProtocol];
	
	/***********************************************************************************/
	/// 先循环所有 精灵 的 ai函数(所有需要在屏幕上显示的精灵, 都会挂接在 ScreenSpritesLayer 中, 
	/// 包括已经死亡的但是需要留下尸体的精灵)
	/// 那些已经死亡, 并且播放玩死亡动画, 并且不需要在屏幕上留下尸体的精灵, 
	/// 会在其内部调用 removeFromParentAndCleanup 函数将自己从其所在的层中删除掉
	for (id sprite in [ScreenSpritesLayer sharedScreenSpritesLayer].children) {
		if (![sprite conformsToProtocol:@protocol(TYAIProtocol)]) {
			/// 异常 : ai方法相当于每个精灵的主逻辑循环方法
			NSAssert(NO, @"某个动画对象没有实现 ai方法");
			continue;
		}
		
		/// 调用精灵的AI方法
		[(id<TYAIProtocol>)sprite ai:delta];
		
		/// 不会在各精灵的AI中直接攻击player, 所有敌对精灵都要通过自己的攻击系统, 创建子弹来攻击player,
		/// 哪怕是近战精灵, 这样可以保持精灵行为的统一性.
	}
	/***********************************************************************************/
	
	
	/***********************************************************************************/
	/// 碰撞相关的一些临时变量
	CGRect a_rect_1;
	CGRect a_rect_2;
	NSInteger a_n_hurt_value = 0;/// 子弹伤害值
	
	/// 循环 检测player的子弹和能够被攻击的精灵数组的碰撞
	for (id playerBullet in a_p_player_bullet_array) {
		
		/// 判断player当前子弹是否实现了 碰撞接口/并且具有伤害值/并且实现了碰撞目标后的通知协议
		if (   ! [playerBullet conformsToProtocol:@protocol(TYCollisionProtocol)]
				|| ! [playerBullet conformsToProtocol:@protocol(TYHurtValueProtocol)]
				|| ! [playerBullet conformsToProtocol:@protocol(TYPlayerBulletCollisionToTarget)]) {
			/// 异常
			NSAssert(NO, @"player某个子弹, 没有实现必须的协议!");
			continue;
		}
		
		/// 获取 当前player子弹的碰撞矩形
		a_rect_1 = [(id<TYCollisionProtocol>)playerBullet getCollisionRect];
		/// 获取 当前palyer子弹的伤害值
		a_n_hurt_value = [(id<TYHurtValueProtocol>)playerBullet getHurtValue];
		
		for (id canBeAttackedSprite in a_p_can_be_attacked_sprite_array) {
			
			/// 判断当前精灵是否实现了 碰撞接口 和 被伤害值接口
			if (   ! [canBeAttackedSprite conformsToProtocol:@protocol(TYCollisionProtocol)]
					|| ! [canBeAttackedSprite conformsToProtocol:@protocol(TYBeHurtProtocol)]) {
				/// 异常
				NSAssert(NO, @"某个能被player攻击的精灵, 没有实现必须的协议!");
				continue;
			}
			
			/// 获取当前能被伤害精灵的碰撞矩形
			a_rect_2 = [(id<TYCollisionProtocol>)canBeAttackedSprite getCollisionRect];
			
			/// 碰撞检测
			if (!CGRectIntersectsRect(a_rect_1, a_rect_2)) {
				/// 没有发生碰撞
				continue;
			}
			
			/// 对目标 精灵 进行伤害
			[(id<TYBeHurtProtocol>)canBeAttackedSprite beHurt:a_n_hurt_value];
			
			/// 要判断 能被伤害的精灵是否已经死亡, 死亡的精灵要将其移出其之前的集合
			/// 首先判断目标精灵是否响应isDead方法
			if (![canBeAttackedSprite respondsToSelector:@selector(isDead)]) {
				/// 异常 : 能够被攻击的精灵, 必须挂接生命系统, 并且必须实现 isDead方法
				NSAssert(NO, @"某个精灵没有实现 isDead 方法");
				continue;
			}
			if ([canBeAttackedSprite performSelector:@selector(isDead)]) {
				/// 目标精灵已经死亡, 就将其移出其之前的精灵集合, 精灵死亡后会显示其死亡动画, 这个死亡动画只需要调用其AI方法就能执行,
				/// 精灵在自己的AI方法中判断自己是否需要在屏幕上留下尸体(精灵可通过isNeedShowBons方法来判断是否需要留下尸体, 
				/// 如果不需要留下尸体, 就调用removeFromParentAndCleanup将自己从自己所在的层中删除即可)
				[a_p_can_be_attacked_sprite_array removeObject:canBeAttackedSprite];
			}
			
			/// player的子弹很特殊, 具有持续性伤害, 不跟敌对精灵的子弹一样, 碰到player就要爆炸消失,
			/// 所以player子弹和敌人子弹继承不同的"碰撞到目标通知接口", 由player子弹自己决定何时从其父集合中删除
			/// 并且从其所在的层中删除自己
			[playerBullet bulletCollisionToTarget:a_p_player_bullet_array];
		}
	}
 
	/// 先取出player的碰撞矩形, 不要每次都在循环中获取
	a_rect_2 = [a_player_communicate player_getCollisionRect];
	
	/// 循环 检测敌人的子弹对player的碰撞
	for (id enemyBullet in a_p_enemy_bullet_array) {
		/// 判断敌人子弹是否实现了 碰撞接口 和 具有攻击力
		if (   ! [enemyBullet conformsToProtocol:@protocol(TYCollisionProtocol)]
				|| ! [enemyBullet conformsToProtocol:@protocol(TYHurtValueProtocol)]
				|| ! [enemyBullet conformsToProtocol:@protocol(TYEnemyBulletCollisionToTarget)]){
			/// 异常
			NSAssert(NO, @"某个敌人子弹 没有实现碰撞接口或者不具有伤害值!");
			continue;
		}
		a_rect_1 = [(id<TYCollisionProtocol>)enemyBullet getCollisionRect];
		
		/// 碰撞检测
		if (CGRectIntersectsRect(a_rect_1, a_rect_2)) {
			/// 获取 敌人子弹 的伤害值
			a_n_hurt_value = [(id<TYHurtValueProtocol>)enemyBullet getHurtValue];
			
			/// 对 player 进行伤害
			[a_player_communicate player_hurtPlayer:a_n_hurt_value];

			if ([a_player_communicate player_isDead]) {
				/// player已经死亡, 不需要再循环其他精灵了
				return;
			}
			
			/// 通知子弹精灵, 它已经撞到了目标(敌方子弹, 此时可以发生爆炸效果)
			[enemyBullet bulletCollisionToTarget];
			
			/// 然后将其移出敌人子弹集合(敌人的子弹是不需要留下尸体的, 所以在其播放完死亡动画后, 可以调用
			/// removeFromParentAndCleanup 将其自己从其所在的层中删除.)
			[a_p_enemy_bullet_array removeObject:enemyBullet];
		}
	}
}

- (void) deallocMe {
	[self dealloc];
}

@end
